/*
 * bill.cpp
 *
 *  Created on: Dec 26, 2013
 *      Author: killerg
 */

#include "bill_deps.h"
#include "bill.h"
#include "bill_console.h"
#include "bill_cfg.h"
#include "code.h"


#include "share/clock.h"
#include "share/http_s.h"
#include "share/db_mgr.h"
#include "share/util.h"
#include "share/msg.h"
#include "share/util.h"

#include "version.h"

#include <event2/keyvalq_struct.h>
#include <sys/queue.h>

bool init_lj();
bool init_uc();
bool init_360();
bool init_91();
bool init_au();

bill_t g_bill;

static void handle_ctrl_c(int signal) {
    g_bill.svcdata->shut = true;
}

static int log_cb(int mask, const char* fmt, ...) {
    va_list arg;
    va_start(arg, fmt);
    int n = g_console->vlog(mask, fmt, arg);
    va_end(arg);
    return n;
}

static int vlog_cb(int mask, const char* fmt, va_list arg) {
    int n = g_console->vlog(mask, fmt, arg);
    return n;
}


bool bill_t::init(SvcData* svcdata_) {
	on_signal(SIGINT, handle_ctrl_c);
	sig_ignore(SIGPIPE);

	svcdata = svcdata_;
	cfg = new bill_cfg_t;
    console = new bill_console_t;
    clock = new my_clock_t;
    db = new db_mgr_t;
    svrmgr = new server_mgr_t;
    https = new http_server;
    sessmgr = new serversess_mgr_t;
    code = new code_t;

    std::string logname = fmt_cstr("bill_%s", svcdata->prefix);
    if (!console->init_log(logname.c_str())) {
    	//printf("g_console log init failed\r\n");
        return false;
    }

    util_logcb = log_cb;
    util_vlogcb = vlog_cb;

    UTIL_LOG(I, "branch:%s, commit:%s", GIT_BRANCH, GIT_COMMIT_HASH);

    UTIL_LOG(I, "start init");

    if (!cfg->init(svcdata->prefix)) {
        UTIL_LOG(E, "g_cfg init failed");
        return false;
    }

    if (!console->init()) {
        UTIL_LOG(E, "g_console init failed");
        return false;
    }

    if (!console->start_accept(cfg->ListenConsoleIp.c_str(), cfg->ListenConsolePort)) {
        UTIL_LOG(E, "g_console start accept err init failed");
        return false;
    }

    if (!clock->init(1000)) {
        UTIL_LOG(E, "g_clock init failed");
        return false;
    }

    if (!db->init(cfg->DbHost.c_str(), "", "", cfg->DbBucket.c_str())) {
        UTIL_LOG(E, "g_db init failed");
        return false;
    }

    console->watch_n("run_sec", [this]()->int{ return int(clock->eclipse); });
    console->watch_f("load", [this]()->double{ return clock->frame_busy; }, [this](){return clock->tick_len;});
    console->watch_n("db_ok", [this]()->int32_t{ return db->ok(); });

    if (!svrmgr->init()) {
        UTIL_LOG(E, "g_svrmgr init failed");
        return false;
    }

    if (!https->init("0.0.0.0", cfg->HttpListenPort)) {
        UTIL_LOG(E, "g_https init failed");
        return false;
    }

    if (!sessmgr->init()) {
        UTIL_LOG(E, "g_sessmgr init failed");
        return false;
    }

    if (!code->init()) {
        UTIL_LOG(E, "g_code start accept err init failed");
        return false;
    }

    if (!init_lj()) {
        UTIL_LOG(E, "init_xiaomi err init failed");
        return false;
    }

    if (!init_uc()) {
        UTIL_LOG(E, "init_xiaomi err init failed");
        return false;
    }

    if (!init_91()) {
        UTIL_LOG(E, "init_91 err init failed");
        return false;
    }

    if (!init_360()) {
        UTIL_LOG(E, "init_360 err init failed");
        return false;
    }

    if (!init_au()) {
        UTIL_LOG(E, "init_360 err init failed");
        return false;
    }

     UTIL_LOG(I, "end init");
    return true;
}

void bill_t::destroy() {

    UTIL_LOG(I, "start destroy");

    code->destroy();
    sessmgr->destroy();
    https->destroy();
    svrmgr->destroy();
    db->destroy();
    clock->destroy();
    cfg->destroy();

    UTIL_LOG(I, "end destroy");

    console->destroy();

    safe_del(code);
    safe_del(sessmgr);
    safe_del(https);
    safe_del(svrmgr);
    safe_del(db);
    safe_del(clock);
    safe_del(console);
    safe_del(cfg);
}

void bill_t::loop() {
    UTIL_LOG(I, "start loop");
    while (!svcdata->shut) {
        clock->begin_update();
        sessmgr->update(clock->delta);
        svrmgr->update();
        https->update();
        db->update();
        console->update();
        code->update();
        clock->end_update();
        clock->wait_frame();
        if (clock->sec_jump) {
            console->update_watcher();
            UTIL_LOG(C, "\n%s", console->watch_ss.str().c_str());
        }
        svcdata->refresh;
    }
    UTIL_LOG(I, "end loop");
}

void log_bill_err(const char* plat, const char* why, const char* query) {
    char buff[100];
    time_t now = time(NULL);
    strftime(buff,100,"%Y%m%d_%H%M%S",localtime(&now));
	UTIL_LOG(E, "plat:%s why:%s body:%s", plat, why, query);

}
